/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package AlgoritmoPronostico;

import beans.Carro;
import beans.Mapa;
import beans.Moto;
import beans.Path;
import beans.Pedido;
import beans.Punto;
import beans.Vehiculo;
import colonia.Nodo;
import facade.PronosticoFacade;
import java.util.ArrayList;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

/**
 *
 * @author Ahmed
 */
public class GestorVehiculos {
    private static GestorVehiculos _instancia;
    private ArrayList<Vehiculo> _vehiculos = new ArrayList<>();
    private boolean encontrado=false;
    
    public String getJson(int idCarro, int idPedido, int idCliente){ 
        String hora = Reloj.getInstancia().getFechaString("HH:mm");
        String fecha = Reloj.getInstancia().getFechaString("dd-MM-yyyy");
        JSONObject obj = new JSONObject();
        JSONArray vehiculosJson = new JSONArray();
        int tam = this._vehiculos.size();
        for(int i =0; i < tam ; i++){ 
            JSONObject v = new JSONObject();
            JSONArray ruta = new JSONArray(); 
            Path listaRuta = this._vehiculos.get(i).getRuta(); 
            int tamRuta = listaRuta.size();
            for(int j =0; j < tamRuta;j++){
                JSONObject punto = new JSONObject(); 
                punto.put("x", listaRuta.get(j).getX());
                punto.put("y", listaRuta.get(j).getY());
                ruta.add(punto);
            }
            v.put("ruta",ruta);
            JSONArray pedidos = new JSONArray();
            try{
            ArrayList<Pedido> listaPedidos = (ArrayList<Pedido>)this._vehiculos.get(i).getListaPedido().clone();
            
            int tamPedido = listaPedidos.size();
            for(int j =0; j < tamPedido;j++){
                JSONObject pedido = new JSONObject(); 
                pedido.put("x", listaPedidos.get(j).getDestino().getX());
                pedido.put("y", listaPedidos.get(j).getDestino().getY());
                pedido.put("cp", listaPedidos.get(j).getDemanda());
                long minRest = (listaPedidos.get(j).getFechaVencimiento().getTimeInMillis()-Reloj.getInstancia().getFecha().getTimeInMillis())/60000;
                pedido.put("minutosRestantes",minRest);
                pedidos.add(pedido);
            }
            }catch(Exception e){
                String asd = e.toString();
            }
            v.put("pedidos",pedidos);
            v.put("x",this._vehiculos.get(i).getPosicionActual().getX());
            v.put("y",this._vehiculos.get(i).getPosicionActual().getY());
            if (((i==idCarro) || (idCarro==-1)) && (idPedido==-1) && (idCliente==-1)){
                 vehiculosJson.add(v);
            }
            if ((idPedido!=-1)&& (idCarro==-1) && (idCliente==-1)){
               for (int j=0; j<this._vehiculos.get(i).getListaPedido().size();j++){
                   if ((idPedido==this._vehiculos.get(i).getListaPedido().get(j).getIdPedido()) && (this._vehiculos.get(i).getListaPedido().get(j).getEstadoPedido()=="Pendiente")){
                       vehiculosJson.add(v);
                       encontrado=true;
                   }
               }
               if (encontrado==false) {
                   //Mostrar mensaje de que pedido ya fue entregado
               }
              
           } 
                    
            
        }
        obj.put("vehiculos", vehiculosJson);
        obj.put("reloj",hora);
        obj.put("fecha",fecha);
        JSONArray pedidosJson = new JSONArray();
        for(int i =0;i< PronosticoFacade.pedidos.size();i++){
            JSONObject pedido = new JSONObject();
            pedido.put("x", PronosticoFacade.pedidos.get(i).getDestino().getX());
            pedido.put("y", PronosticoFacade.pedidos.get(i).getDestino().getY());
            pedido.put("cp",PronosticoFacade.pedidos.get(i).getDemanda());
            pedidosJson.add(pedido);
        }
        obj.put("pedidos", pedidosJson);
        return obj.toJSONString();
    }
    
    public ArrayList<Vehiculo> getVehiculos() {
        return _vehiculos;
    }
    
    public static GestorVehiculos getInstancia(){
        if (_instancia == null) 
            _instancia = new GestorVehiculos();
        return _instancia;
    }
    
    private GestorVehiculos(){
    }
    
    public void crearVehiculos (){
        int i = 0;
        int contMoto = 0;
        int contCarro = 0;
        for (; i < Parametros.getNumCarros()+Parametros.getNumMotos(); i++){
            if (Math.random()<=0.5){
                contCarro++;
                _vehiculos.add(new Carro(""));
            }else { 
                _vehiculos.add(new Moto(""));
                contMoto++;
            }
            if (contMoto == Parametros.getNumMotos()){
                i++;
                for (; i < Parametros.getNumCarros()+Parametros.getNumMotos(); i++){
                _vehiculos.add(new Carro(" "));
                }
            }
            if (contCarro == Parametros.getNumCarros()){
                i++;
                for (;i < Parametros.getNumCarros()+Parametros.getNumMotos(); i++){
                    _vehiculos.add(new Moto(" "));
                }
            }
        }        
    }
    
    public Vehiculo getVehiculo(int index){
        return _vehiculos.get(index);
    }
    
    
    
    public void actualizarVehiculosYOrdenes(int tiempo,ArrayList<Pedido> ordenes){
        int size = this._vehiculos.size();
        for(int i=0;i<size;i++){
            this._vehiculos.get(i).avanzarP(tiempo,ordenes);
        }
    }
    
    public static float geomDistance(Punto p1, Punto p2){
        int x1 = p1.getX();
        int x2 = p2.getX();
        int y1 = p1.getY();
        int y2 = p2.getY();
        return (float) Math.sqrt((x1-x2)*(x1-x2) +(y1-y2)*(y1-y2));
    }
    
    private static ArrayList<Punto> getShortestRoute(ArrayList<ArrayList<Punto>> routes, Punto p) {
        ArrayList<Punto> shortest = null;
        float minTime = Float.POSITIVE_INFINITY;
        for(int i=0;i<routes.size();i++){
            ArrayList<Punto> current = routes.get(i);
            //añadir el costo de las aristas en caso se necesite aristas de difernte peso
            float time = geomDistance(current.get(current.size()-1),p);
            if(time <= minTime){
                minTime = time;
                shortest = current;
            }
        }
        routes.remove(shortest);
        return shortest;
    }
    
    public static ArrayList<Punto> Astar(Punto p1, Punto p2){
        ArrayList<ArrayList<Punto>> routes = new ArrayList<ArrayList<Punto>>();
        ArrayList<Punto> visitados = new ArrayList<Punto>();
        //inicializar una ruta con el nodo inicial
        ArrayList<Punto> route = new ArrayList<Punto>();
        route.add(p1);
        routes.add(route);
        
        while(visitados.size() != Mapa.size()){
            ArrayList<Punto> cheapest = getShortestRoute(routes,p2);
            Punto ultimo = cheapest.get(cheapest.size()-1);
            if(ultimo == p2)return cheapest;
            for(int i=0;i < ultimo.getnAdj();i++){
                if(!ultimo.getAdj()[i].estaBloqueado() && !visitados.contains(ultimo.getAdj()[i])){
                    ArrayList<Punto> nuevaRuta = (ArrayList<Punto>)cheapest.clone();
                    nuevaRuta.add(ultimo.getAdj()[i]);
                    routes.add(nuevaRuta);
                }
            }
            visitados.add(ultimo);
        }
        return null;
    }

//    public void asignarRutas(ArrayList<ArrayList<colonia.Nodo>> bestRoutes, ArrayList<ArrayList<Pedido>> pedidosAsignados) {
//        for(int i=0;i<bestRoutes.size();i++){
//            ArrayList<Punto> ruta = new ArrayList<>();
//            ArrayList<Nodo> solucion = bestRoutes.get(i);
//            if (solucion == null) continue;
//            for(int j=1;j< solucion.size();j++){
//                Punto p1 = solucion.get(j-1).getPunto();
//                Punto p2 = solucion.get(j).getPunto();
//                ArrayList<Punto> segment = GestorVehiculos.Astar(p1,p2);
//                if(j!=1)segment.remove(0);
//                ruta.addAll(segment);
//            }
//            this._vehiculos.get(i).setRuta(ruta);
//            this._vehiculos.get(i).setListaPedido(pedidosAsignados.get(i));
//        }
//    }
    
    public void asignarRutas(ArrayList<ArrayList<Nodo>> bestRoutes,ArrayList<ArrayList<Pedido>> pedidosAsignados){
        for(int i=0;i<bestRoutes.size();i++){
            ArrayList<Punto> ruta = new ArrayList<>();
            ArrayList<Nodo> solucion = bestRoutes.get(i);
            if (solucion == null) continue;
            for(int j=1;j< solucion.size();j++){
                Punto p1 = solucion.get(j-1).getPunto();
                Punto p2 = solucion.get(j).getPunto();
                ArrayList<Punto> segment = GestorVehiculos.Astar(p1,p2);
                if(j!=1)segment.remove(0);
                ruta.addAll(segment);
            }
            this._vehiculos.get(i).setRuta(ruta);
            this._vehiculos.get(i).setListaPedido(pedidosAsignados.get(i));
        }
    }

    public void actualizaTurno() {
        for (int i=0;i<_vehiculos.size();i++){
            _vehiculos.get(i).setTurno(Reloj.getInstancia().obtenerTurno(Reloj.getInstancia().getHora()));
        } 
    }
}
